home *** CD-ROM | disk | FTP | other *** search
/ Megadoom II / MEGADOOM II - iso.7z / MEGADOOM II.ISO / doom / editors / map / dmpsmu / source / dmpsmu.c < prev    next >
C/C++ Source or Header  |  1994-10-27  |  17KB  |  601 lines

  1. /*
  2.    DooM PostScript Maps Utility, by Frans P. de Vries.
  3.  
  4. Derived from:
  5.  
  6.    Doom Editor Utility, by Brendon Wyber and Raphaδl Quinet.
  7.  
  8.    You are allowed to use any parts of this code in another program, as
  9.    long as you give credits to the authors in the documentation and in
  10.    the program itself.  Read the file README for more information.
  11.  
  12.    This program comes with absolutely no warranty.
  13.  
  14.    DMPSMU.C - Main program routines for interactive utility.
  15. */
  16.  
  17.  
  18. /* the includes */
  19. #include "dmps.h"
  20.  
  21.  
  22. /* global variables */
  23. Bool Registered = FALSE;    /* registered or shareware WAD file? */
  24. Bool Commercial = FALSE;    /* DOOM ][ or DOOM WAD file? */
  25. char *MainWad   = "DOOM.WAD";    /* name of the main WAD file */
  26. char *UserLvlNm = NULL;        /* user defined level name */
  27.  
  28.  
  29. /* local variables */
  30. char **PatchWads = NULL;    /* list of patch WAD files */
  31.  
  32. OptDesc options[] =        /* description of the command line options */
  33. {
  34. /*   short & long names    type        message if true/changed    message if false    where to store the value */
  35.    { "W",  "MAIN",    OPT_STRING,    "Main WAD file",    NULL,            &MainWad    },
  36.    { "PW", "PWAD",    OPT_STRINGACC,    "Patch WAD file",    NULL,            &PatchWads    },
  37.    { "",   "FILE",    OPT_STRINGLIST,    "Patch WAD file",    NULL,            &PatchWads    },
  38.    { NULL, NULL,    OPT_END,    NULL,            NULL,            NULL        }
  39. };
  40.  
  41.  
  42. /*
  43.    the main program
  44. */
  45. int main( int argc, char *argv[])
  46. {
  47.    BCINT i;
  48.  
  49.    Credits( stdout);
  50.    argv++;
  51.    argc--;
  52.    /* read command line options */
  53.    ParseCommandLineOptions( argc, argv);
  54.  
  55.    /* load the Wad files */
  56.    OpenMainWad( MainWad);
  57.    if (PatchWads)
  58.       while (PatchWads[ 0])
  59.       {
  60.      OpenPatchWad( PatchWads[ 0]);
  61.      PatchWads++;
  62.       }
  63.    /* sanity check */
  64.    CloseUnusedWadFiles();
  65.  
  66.    /* all systems go! */
  67.    MainLoop();
  68.    /* that's all, folks! */
  69.    CloseWadFiles();
  70.    exit( 0);
  71. }
  72.  
  73.  
  74. /*
  75.    append a string to a null-terminated string list
  76. */
  77. void AppendItemToList( char ***list, char *item)
  78. {
  79.    BCINT i = 0;
  80.  
  81.    if (*list)
  82.    {
  83.       /* count the number of elements in the list (last = null) */
  84.       while ((*list)[ i])
  85.      i++;
  86.       /* expand the list */
  87.       *list = (char **) ResizeMemory( *list, (i + 2) * sizeof( char **));
  88.    }
  89.    else
  90.       /* create a new list */
  91.       *list = (char **) GetMemory( 2 * sizeof( char **));
  92.  
  93.    /* append the new element */
  94.    (*list)[ i] = item;
  95.    (*list)[ i + 1] = NULL;
  96. }
  97.  
  98.  
  99. /*
  100.    handle command line options
  101. */
  102. void ParseCommandLineOptions( int argc, char *argv[])
  103. {
  104.    BCINT optnum;
  105.  
  106.    while (argc > 0)
  107.    {
  108.       if (argv[ 0][ 0] != '-' && argv[ 0][ 0] != '+')
  109.      ProgError( "options must start with '-' or '+'");
  110.       strupr( argv[ 0]);
  111.       if (!strcmp( argv[ 0], "-?") || !strcmp( argv[ 0], "-H") ||
  112.       !strcmp( argv[ 0], "-HELP"))
  113.       {
  114.      Usage( stdout);
  115.      exit( 0);
  116.       }
  117.       for (optnum = 0; options[ optnum].opt_type != OPT_END; optnum++)
  118.       {
  119.      if (!strcmp( &(argv[ 0][ 1]), options[ optnum].short_name) ||
  120.          !strcmp( &(argv[ 0][ 1]), options[ optnum].long_name))
  121.      {
  122.         switch (options[ optnum].opt_type)
  123.         {
  124.         case OPT_BOOLEAN:
  125.            if (argv[ 0][ 0] == '-')
  126.            {
  127.           *((Bool *) (options[ optnum].data_ptr)) = TRUE;
  128.           if (options[ optnum].msg_if_true)
  129.              printf( "%s.\n", options[ optnum].msg_if_true);
  130.            }
  131.            else
  132.            {
  133.           *((Bool *) (options[ optnum].data_ptr)) = FALSE;
  134.           if (options[ optnum].msg_if_false)
  135.              printf( "%s.\n", options[ optnum].msg_if_false);
  136.            }
  137.            break;
  138.         case OPT_INTEGER:
  139.            if (argc <= 1)
  140.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  141.            argv++;
  142.            argc--;
  143.            *((BCINT *) (options[ optnum].data_ptr)) = atoi( argv[ 0]);
  144.            if (options[ optnum].msg_if_true)
  145.           printf( "%s: %d.\n", options[ optnum].msg_if_true, atoi( argv[ 0]));
  146.            break;
  147.         case OPT_STRING:
  148.            if (argc <= 1)
  149.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  150.            argv++;
  151.            argc--;
  152.            *((char **) (options[ optnum].data_ptr)) = argv[ 0];
  153.            if (options[ optnum].msg_if_true)
  154.           printf( "%s: %s.\n", options[ optnum].msg_if_true, argv[ 0]);
  155.            break;
  156.         case OPT_STRINGACC:
  157.            if (argc <= 1)
  158.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  159.            argv++;
  160.            argc--;
  161.            AppendItemToList( (char ***) options[ optnum].data_ptr, argv[ 0]);
  162.            if (options[ optnum].msg_if_true)
  163.           printf( "%s: %s.\n", options[ optnum].msg_if_true, argv[ 0]);
  164.            break;
  165.         case OPT_STRINGLIST:
  166.            if (argc <= 1)
  167.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  168.            while (argc > 1 && argv[ 1][ 0] != '-' && argv[ 1][ 0] != '+')
  169.            {
  170.           argv++;
  171.           argc--;
  172.           AppendItemToList( (char ***) options[ optnum].data_ptr, argv[ 0]);
  173.           if (options[ optnum].msg_if_true)
  174.              printf( "%s: %s.\n", options[ optnum].msg_if_true, argv[ 0]);
  175.            }
  176.            break;
  177.         default:
  178.            ProgError( "unknown option type (BUG!)");
  179.         }
  180.         break;
  181.      }
  182.       }
  183.       if (options[ optnum].opt_type == OPT_END)
  184.      ProgError( "invalid argument: \"%s\"", argv[ 0]);
  185.       argv++;
  186.       argc--;
  187.    }
  188. }
  189.  
  190.  
  191. /*
  192.    output the program usage to the specified file
  193. */
  194. void Usage( FILE *where)
  195. {
  196.    fprintf( where, "Usage:\n");
  197.    fprintf( where, "dmpsmu  [-w <main_wad_file>] [-pw <pwad_file>] [-file <pwad_files>...]\n");
  198.    fprintf( where, "   -w    Gives the name of the main WAD file (also -main)  Default is DOOM.WAD\n");
  199.    fprintf( where, "   -pw   To add one patch WAD file to be loaded; may be repeated (also -pwad)\n");
  200.    fprintf( where, "   -file To add a list of patch WAD files to be loaded\n");
  201. /* fprintf( where, "Put a '+' instead of a '-' before boolean options to reverse their effect\n"); */
  202. }
  203.  
  204.  
  205. /*
  206.    output the credits of the program to the specified file
  207. */
  208. void Credits( FILE *where)
  209. {
  210.    fprintf( where, "DMPSMU: DooM PostScript Maps Utility, ver %s\n", DMPS_VERSION);
  211.    fprintf( where, " By Frans P. de Vries (fpv@xymph.iaf.nl)\n");
  212.    fprintf( where, "[Derived from DEU v%s by Brendon Wyber and Raphaδl Quinet]\n\n", DEU_VERSION);
  213. /* fprintf( where, "Derived from DEU: Doom Editor Utility, ver %s\n\n", DEU_VERSION);
  214.    fprintf( where, " By Raphaδl Quinet (quinet@montefiore.ulg.ac.be)\n"
  215.            "and Brendon J. Wyber (b.wyber@csc.canterbury.ac.nz)\n"
  216.            " Ported to DJGPP/GO32 by Per Allansson (c91peral@und.ida.liu.se)\n"
  217.            "and Per Kofod (per@ollie.dnk.hp.com)\n\n"); */
  218. }
  219.  
  220.  
  221. /*
  222.    terminate the program reporting an error
  223. */
  224. void ProgError( char *errstr, ...)
  225. {
  226.    va_list args;
  227.  
  228.    va_start( args, errstr);
  229.    printf( "\nProgram Error: *** ");
  230.    vprintf( errstr, args);
  231.    printf( " ***\n");
  232.    va_end( args);
  233.    /* clean up & free space */
  234.    ForgetLevelData();
  235.    CloseWadFiles();
  236.    exit( 1);
  237. }
  238.  
  239.  
  240. /*
  241.    the main program menu loop
  242. */
  243. void MainLoop()
  244. {
  245.    WadPtr wad;
  246.    FILE *file;
  247.    char input[ 120];
  248.    char *com, *out;
  249.    BCINT episode, mission;
  250.  
  251.    for (;;)
  252.    {
  253.       /* get the input */
  254.       printf( "\n[? for help]> ");
  255.       gets( input);
  256.       printf( "\n");
  257.  
  258.       /* eat the white space and get the first command word */
  259.       com = strtok( input, " ");
  260.       strupr( com);
  261.  
  262.       /* user just hit return */
  263.       if (com == NULL)
  264.      printf( "[Please enter a command or ? for help.]\n");
  265.  
  266.       /* user inputting for help */
  267.       else if (!strcmp( com, "?") || !strcmp( com, "HELP") || !strcmp( com, "H"))
  268.       {
  269.      printf( "? or H[elp]                       -- to display this text\n");
  270.      printf( "A[nalyze] episode mission         -- to analyze a game level's statistics\n");
  271.      printf( "D[ump] <DirEntry> [outfile]       -- to dump a directory entry in hex\n");
  272.      printf( "F[lags] { <+-><24ABDEFGLMNPSTUZ>} -- to display/set the print flags\n");
  273.      printf( "L[ist] <WadFile> [outfile]        -- to list the directory of a WAD file\n");
  274.      printf( "M[aster] [outfile]                -- to list the master directory\n");
  275.      printf( "N[ame] [name or '']               -- to display/set the user level name\n");
  276.      printf( "P[rint] episode mission <PSfile>  -- to print a game level to a PostScript file\n");
  277.      printf( "Q[uit]                            -- to quit\n");
  278.      printf( "R[ead] <WadFile>                  -- to read a new WAD patch file\n");
  279.      printf( "W[ads]                            -- to display the open WAD files\n");
  280.      printf( "X[tract] <DirEntry> <RawFile>     -- to save (extract) one object to a raw file\n");
  281.       }
  282.  
  283.       /* user asked for list of open WAD files */
  284.       else if (!strcmp( com, "WADS") || !strcmp( com, "W"))
  285.       {
  286.      printf( "%-20s  IWAD  (Main %s WAD file)\n", WadFileList->filename,
  287.           (Commercial ? "Commercial" : (Registered ? "Registered" : "Shareware")));
  288.      for (wad = WadFileList->next; wad; wad = wad->next)
  289.      {
  290.         if (Commercial && wad->directory[ 0].name[ 0] == 'M' &&
  291.                   wad->directory[ 0].name[ 1] == 'A' &&
  292.                   wad->directory[ 0].name[ 2] == 'P')
  293.            printf( "%-20s  PWAD  (Patch WAD file for level %c%c)\n",
  294.             wad->filename, wad->directory[ 0].name[ 3], wad->directory[ 0].name[ 4]);
  295.         else if (! Commercial && wad->directory[ 0].name[ 0] == 'E' &&
  296.                      wad->directory[ 0].name[ 2] == 'M')
  297.            printf( "%-20s  PWAD  (Patch WAD file for episode %c mission %c)\n",
  298.             wad->filename, wad->directory[ 0].name[ 1], wad->directory[ 0].name[ 3]);
  299.         else
  300.         {
  301.            /* kludge */
  302.            strncpy( input, wad->directory[ 0].name, 8);
  303.            input[ 8] = '\0';
  304.            printf( "%-20s  PWAD  (Patch WAD file for %s)\n", wad->filename, input);
  305.         }
  306.      }
  307.       }
  308.  
  309.       /* user asked to quit */
  310.       else if (!strcmp( com, "QUIT") || !strcmp( com, "Q"))
  311.       {
  312.      if (! Registered && ! Commercial)
  313.         printf("Remember to register your copy of DOOM!\n");
  314.      printf( "Goodbye...\n");
  315.      break;
  316.       }
  317.  
  318.       /* user asked to display/set the print flags */
  319.       else if (!strcmp( com, "FLAGS") || !strcmp( com, "F"))
  320.       {
  321.      com = strtok( NULL, " ");
  322.      if (com == NULL)
  323.         DisplayFlags();
  324.      else
  325.         while (com != NULL)
  326.         {
  327.            strupr( com);
  328.            if (com[ 0] != '+' && com[ 0] != '-')
  329.           printf( "[Flag must start with '+' or '-'.]\n");
  330.            else if (!strchr( "24ABDEFGLMNPSTUZ", com[ 1]))
  331.           printf( "[Flag must be one of '24ABDEFGLMNPSTUZ'.]\n");
  332.            else if (com[ 2] != ' ' && com[ 2] != '\0')
  333.           printf( "[Flag must be one character.]\n");
  334.            else
  335.           SetFlag( com[ 1], com[ 0]);
  336.            com = strtok( NULL, " ");
  337.         }
  338.       }
  339.  
  340.       /* user asked to display/set the user level name */
  341.       else if (!strcmp( com, "NAME") || !strcmp( com, "N"))
  342.       {
  343.      com = strtok( NULL, " ");
  344.      if (com == NULL)
  345.         if (UserLvlNm != NULL)
  346.            printf( "User level name : %s\n", UserLvlNm);
  347.         else
  348.            printf( "[User level name not set.]\n");
  349.      else
  350.         if (! strcmp( com, "''"))
  351.         {
  352.            /* reset user level name */
  353.            FreeMemory( UserLvlNm);
  354.            UserLvlNm = NULL;
  355.            printf( "User level name reset\n");
  356.         }
  357.         else
  358.         {
  359.            /* set user level name */
  360.            UserLvlNm = (char *) GetMemory( (strlen( com) + 1) * sizeof( char));
  361.            strcpy( UserLvlNm, com);
  362.            printf( "User level name set : %s\n", UserLvlNm);
  363.         }
  364.       }
  365.  
  366.       /* user asked to print a level */
  367.       else if (!strcmp( com, "PRINT") || !strcmp( com, "P"))
  368.       {
  369.      com = strtok( NULL, " ");
  370.      if (com == NULL)
  371.      {
  372.         printf( "[Episode number argument missing.]\n");
  373.         continue;
  374.      }
  375.      episode = atoi( com);
  376.      if (Commercial && episode != 0 ||
  377.          ! Commercial && (episode < 1 || episode > (Registered ? 3 : 1)))
  378.      {
  379.         printf( "[Invalid game episode number (%s).]\n", com);
  380.         continue;
  381.      }
  382.      com = strtok( NULL, " ");
  383.      if (com == NULL)
  384.      {
  385.         printf( "[Mission number argument missing.]\n");
  386.         continue;
  387.      }
  388.      mission = atoi( com);
  389.      if (mission < 1 || mission > (Commercial ? 32 : 9))
  390.      {
  391.         printf( "[Invalid game mission number (%s).]\n", com);
  392.         continue;
  393.      }
  394.      out = strtok( NULL, " ");
  395.      if (! out)
  396.      {
  397.         printf( "[PostScript file name argument missing.]\n");
  398.         continue;
  399.      }
  400.      if (Commercial)
  401.         printf( "Outputting PostScript map of level MAP%02d to \"%s\".\n",
  402.              mission, out);
  403.      else
  404.         printf( "Outputting PostScript map of level E%dM%d to \"%s\".\n",
  405.              episode, mission, out);
  406.      if ((PSFile = fopen( out, "wt")) == NULL)
  407.         ProgError( "error opening output file \"%s\"", out);
  408.      fprintf( PSFile, "%%! DMPSMU: DooM PostScript Maps Utility, ver %s\n",
  409.                DMPS_VERSION);
  410.      PrintLevel( episode, mission);
  411.      fprintf( PSFile, "\n%%%% End of file.\n");
  412.      fclose( PSFile);
  413.       }
  414.  
  415.       /* user asked to analyze a level */
  416.       else if (!strcmp( com, "ANALYZE") || !strcmp( com, "A"))
  417.       {
  418.      com = strtok( NULL, " ");
  419.      if (com == NULL)
  420.      {
  421.         printf( "[Episode number argument missing.]\n");
  422.         continue;
  423.      }
  424.      episode = atoi( com);
  425.      if (Commercial && episode != 0 ||
  426.          ! Commercial && (episode < 1 || episode > (Registered ? 3 : 1)))
  427.      {
  428.         printf( "[Invalid game episode number (%s).]\n", com);
  429.         continue;
  430.      }
  431.      com = strtok( NULL, " ");
  432.      if (com == NULL)
  433.      {
  434.         printf( "[Mission number argument missing.]\n");
  435.         continue;
  436.      }
  437.      mission = atoi( com);
  438.      if (mission < 1 || mission > (Commercial ? 32 : 9))
  439.      {
  440.         printf( "[Invalid game mission number (%s).]\n", com);
  441.         continue;
  442.      }
  443.      AnalyzeLevel( episode, mission);
  444.       }
  445.  
  446.       /* user ask for a listing of a WAD file */
  447.       else if (!strcmp( com, "LIST") || !strcmp( com, "L"))
  448.       {
  449.      com = strtok( NULL, " ");
  450.      if (com == NULL)
  451.      {
  452.         printf( "[Wad file name argument missing.]\n");
  453.         continue;
  454.      }
  455.      for (wad = WadFileList; wad; wad = wad->next)
  456.         if (!strcmp( com, wad->filename))
  457.            break;
  458.      if (! wad)
  459.      {
  460.         printf( "[Wad file \"%s\" is not open.]\n", com);
  461.         continue;
  462.      }
  463.      out = strtok( NULL, " ");
  464.      if (out)
  465.      {
  466.         printf( "Outputting directory of \"%s\" to \"%s\".\n", wad->filename, out);
  467.         if ((file = fopen( out, "wt")) == NULL)
  468.            ProgError( "error opening output file \"%s\"", out);
  469.         Credits( file);
  470.         ListFileDirectory( file, wad);
  471.         fprintf( file, "\nEnd of file.\n");
  472.         fclose( file);
  473.      }
  474.      else
  475.         ListFileDirectory( stdout, wad);
  476.       }
  477.  
  478.       /* user asked for the list of the master directory */
  479.       else if (!strcmp( com, "MASTER") || !strcmp( com, "M"))
  480.       {
  481.      out = strtok( NULL, " ");
  482.      if (out)
  483.      {
  484.         printf( "Outputting master directory to \"%s\".\n", out);
  485.         if ((file = fopen( out, "wt")) == NULL)
  486.            ProgError( "error opening output file \"%s\"", out);
  487.         Credits( file);
  488.         ListMasterDirectory( file);
  489.         fprintf( file, "\nEnd of file.\n");
  490.         fclose( file);
  491.      }
  492.      else
  493.         ListMasterDirectory( stdout);
  494.       }
  495.  
  496.       /* user asked to read a new patch WAD file */
  497.       else if (!strcmp( com, "READ") || !strcmp( com, "R"))
  498.       {
  499.      com = strtok( NULL, " ");
  500.      if (com == NULL)
  501.      {
  502.         printf( "[Wad file name argument missing.]\n");
  503.         continue;
  504.      }
  505.      out = strtok( NULL, " ");
  506.      if (out)
  507.         *out = '\0';
  508.      out = (char *) GetMemory( (strlen( com) + 1) * sizeof( char));
  509.      strcpy( out, com);
  510.      OpenPatchWad( out);
  511.      CloseUnusedWadFiles();
  512.       }
  513.  
  514.       /* user asked to dump the contents of a WAD file entry */
  515.       else if (!strcmp( com, "DUMP") || !strcmp( com, "D"))
  516.       {
  517.      com = strtok( NULL, " ");
  518.      if (com == NULL)
  519.      {
  520.         printf( "[Object name argument missing.]\n");
  521.         continue;
  522.      }
  523.      strupr( com);
  524.      out = strtok( NULL, " ");
  525.      if (out)
  526.      {
  527.         printf( "Outputting directory entry data to \"%s\".\n", out);
  528.         if ((file = fopen( out, "wt")) == NULL)
  529.            ProgError( "error opening output file \"%s\"", out);
  530.         Credits( file);
  531.         DumpDirectoryEntry( file, com);
  532.         fprintf( file, "\nEnd of file.\n");
  533.         fclose( file);
  534.      }
  535.      else
  536.         DumpDirectoryEntry( stdout, com);
  537.       }
  538.  
  539.       /* user asked to extract an object to a raw binary file */
  540.       else if (!strcmp( com, "XTRACT") || !strcmp( com, "X") || !strcmp( com, "EXTRACT"))
  541.       {
  542.      com = strtok( NULL, " ");
  543.      if (com == NULL)
  544.      {
  545.         printf( "[Object name argument missing.]\n");
  546.         continue;
  547.      }
  548.      if (strlen( com) > 8 || strchr( com, '.'))
  549.      {
  550.         printf( "[Invalid object name.]\n");
  551.         continue;
  552.      }
  553.      strupr( com);
  554.      out = strtok( NULL, " ");
  555.      if (! out)
  556.      {
  557.         printf( "[Raw file name argument missing.]\n");
  558.         continue;
  559.      }
  560.      for (wad = WadFileList; wad; wad = wad->next)
  561.         if (!strcmp( out, wad->filename))
  562.            break;
  563.      if (wad)
  564.      {
  565.         printf( "[You may not overwrite an opened Wad file with raw data.]\n");
  566.         continue;
  567.      }
  568.      printf( "Saving directory entry data to \"%s\".\n", out);
  569.      if ((file = fopen( out, "wb")) == NULL)
  570.         ProgError( "error opening output file \"%s\"", out);
  571.      SaveEntryToRawFile( file, com);
  572.      fclose( file);
  573.       }
  574.  
  575.       /* unknown command */
  576.       else
  577.      printf( "[Unknown command \"%s\"!]\n", com);
  578.    }
  579. }
  580.  
  581.  
  582. /*
  583.    convert string to uppercase
  584. */
  585. char *strupr( char *str)
  586. {
  587.    char *s = str;
  588.  
  589.    if (str != NULL)
  590.       while (*s)
  591.       {
  592.      if (islower( *s))
  593.         *s = toupper( *s);
  594.      s++;
  595.       }
  596.  
  597.    return str;
  598. }
  599.  
  600. /* end of file */
  601.